package org.linlinjava.litemall.core.storage;

import org.linlinjava.litemall.core.util.CharUtil;
import org.linlinjava.litemall.core.util.MD5Util;
import org.linlinjava.litemall.core.util.PictureUtil;
import org.linlinjava.litemall.db.domain.LitemallStorage;
import org.linlinjava.litemall.db.service.LitemallStorageService;
import org.linlinjava.litemall.db.util.ImageUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.security.NoSuchAlgorithmException;
import java.util.stream.Stream;

/**
 * 提供存储服务类，所有存储服务均由该类对外提供
 */
public class StorageService {
    private String active;
    private Storage storage;
    @Autowired
    private LitemallStorageService litemallStorageService;

    public String getActive() {
        return active;
    }

    public void setActive(String active) {
        this.active = active;
    }

    public Storage getStorage() {
        return storage;
    }

    public void setStorage(Storage storage) {
        this.storage = storage;
    }

    /**
     * 存储一个文件对象
     * @param inputStream   文件输入流
     * @param contentLength 文件长度
     * @param contentType   文件类型
     * @param fileName      文件索引名
     */
    public LitemallStorage store(InputStream inputStream, long contentLength, String contentType, String fileName) {
        //生成20个随机数 + 文件后缀 .jpg
        String key = generateKey(fileName);
        LitemallStorage storageInfo = new LitemallStorage();
        ByteArrayOutputStream baos;
        try {
            //克隆文件输入流
            baos = cloneInputStream(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
        try {
            //以流生成MD5
            String md5 = MD5Util.getMD5(new ByteArrayInputStream(baos.toByteArray()));
            LitemallStorage sameFile = litemallStorageService.findByMd5(md5);

            if (sameFile != null) {
                return sameFile; }
            else {
                storageInfo.setMd5(md5); }
        } catch (NoSuchAlgorithmException | IOException e) {
            e.printStackTrace();
        }
        storage.store(new ByteArrayInputStream(baos.toByteArray()), contentLength, contentType, key);
        contentLength = compression(key, contentLength);
        String url = generateUrl(key);
        String type = fileName.substring(fileName.lastIndexOf(".") + 1);

        storageInfo.setName(fileName);
        storageInfo.setSize((int) contentLength);
        storageInfo.setType(contentType);
        storageInfo.setKey(key);
        storageInfo.setUrl(url);
        litemallStorageService.add(storageInfo);
        if (fileName.indexOf("GOOD_QCODE_") == 0 || moderateContent(url, type)) {
                return storageInfo;
        }
        else {
            storage.delete(key);
            litemallStorageService.deleteByKey(key);
            return null;
        }
    }


    //生成20个随机数 + 文件后缀 .jpg
    private String generateKey(String originalFilename) {
        int index = originalFilename.lastIndexOf('.');
        //得到后缀
        String suffix = originalFilename.substring(index);
        String key = null;
        LitemallStorage storageInfo = null;
        do {
            //生成20个随机数 + 文件后缀 .jpg
            key = CharUtil.getRandomString(20) + suffix;
            storageInfo = litemallStorageService.findByKey(key);
        }
        while (storageInfo != null);

        return key;
    }

    public Stream<Path> loadAll() {
        return storage.loadAll();
    }

    public Path load(String keyName) {
        return storage.load(keyName);
    }

    public Resource loadAsResource(String keyName) {
        return storage.loadAsResource(keyName);
    }

    public void delete(String keyName) {
        storage.delete(keyName);
    }

    private String generateUrl(String keyName) {
        return storage.generateUrl(keyName);
    }

    private Boolean moderateContent(String url, String type) {
        type = type.toLowerCase();
        if ("png".equals(type) || "jpg".equals(type) || "bmp".equals(type) || "gif".equals(type)|| "jpeg".equals(type)) {
            try {
                return PictureUtil.checkImage(url);
            } catch (Exception e) {
                e.printStackTrace();
                return true;
            }
        }
        else {
            return true;
        }
    }

    private long compression(String key, long contentLength) {
        //如果是图片文件
        if (key.contains("jpg") ||key.contains("jpeg") ||key.contains("png") ||key.contains("bmp")) {
            String filePath = System.getProperty("user.dir") + "/storage/" + key;
            return ImageUtil.compressImage(filePath);
        }
        return contentLength;
    }

    private static ByteArrayOutputStream cloneInputStream(InputStream input) throws IOException {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len;
            while ((len = input.read(buffer)) > -1) {
                baos.write(buffer, 0, len);
            }
            baos.flush();
            return baos;
    }

}
